import datetime
import random
from datetime import time


class Action:
    pass


class HangUpAction(Action):
    pass


class HumanTransferAction(Action):
    pass


class ReturnAction(Action):
    pass


class JumperAction(Action):
    def __init__(self, to_node: 'Node'):
        self.to_node = to_node


class Utterance:
    def __init__(self, text: str, duration: int, voice_file: str | None = None, action: Action | None = None,
                 start_time: time | None = None,
                 end_time: time | None = None, is_interrupt_allowed: bool = True):
        self.text = text
        self.duration = duration
        self.voice_file = voice_file
        self.action = action
        self.start_time = start_time
        self.end_time = end_time
        self.is_interrupt_allowed = is_interrupt_allowed


class StrategySwitcher:
    def get_utterance(self, utterances: list[Utterance]) -> Utterance:
        pass


class SequentialSwitcher(StrategySwitcher):
    def get_utterance(self, utterances: list[Utterance]) -> Utterance:
        return utterances[0]


class RandomSwitcher(StrategySwitcher):
    def get_utterance(self, utterances: list[Utterance]) -> Utterance:
        return random.choice(utterances)


class TimeBasedSwitcher(StrategySwitcher):
    def get_utterance(self, utterances: list[Utterance]) -> Utterance:
        now = datetime.time
        result = next((utterance for utterance in utterances if
                       utterance.start_time is not None and utterance.end_time is not None and utterance.start_time < now < utterance.end_time),
                      None)
        if result is None:
            return random.choice(utterances)
        return result


class WaitSetting:
    def __init__(self, timeout: int, utterance: Utterance):
        self.timeout = timeout
        self.utterance = utterance


class NoResponseSetting:
    def __init__(self, timeout: int, utterance: Utterance):
        self.timeout = timeout
        self.utterance = utterance


class BreakSetting:
    def __init__(self, play_time_ratio: float):
        self.play_time_ratio = play_time_ratio


class IntentTemplate:
    def __init__(self, name: str, intent_label: str, keywords: list[str]):
        self.name = name
        self.intent_label = intent_label
        self.keywords = keywords


class Intent:
    def __init__(self, intent_template: IntentTemplate | None = None, keywords: list[str] | None = None):
        self.intent_template = intent_template
        self.keywords = keywords

    def match(self, message: str) -> bool:
        result = False
        # 优先使用关键字匹配
        if not result and self.keywords:  # 先看当前关键字是否能匹配
            result = any((self for keyword in self.keywords if keyword in message))
        if not result and self.intent_template:  # 再看模板关键字是否能匹配
            result = any((self for keyword in self.intent_template.keywords if keyword in message))

        return result


class QASetting:
    def __init__(self, intent: Intent, answers: list[Utterance], strategy_switcher: StrategySwitcher,
                 title: str | None = None):
        self.intent = intent
        self.title = title
        self.answers = answers
        self.strategy_switcher = strategy_switcher

    def get_utterance(self) -> Utterance:
        utterance = self.strategy_switcher.get_utterance(self.answers)
        return utterance


class GlobalSetting:
    def __init__(self, wait_settings: list[WaitSetting], no_response_settings: list[NoResponseSetting],
                 save_settings: list[Utterance], qa_settings: list[QASetting]):
        self.wait_settings = wait_settings
        self.no_response_settings = no_response_settings
        self.save_settings = save_settings
        self.qa_settings = qa_settings


class Branch:
    def __init__(self, intent: Intent, to_node: 'Node', priority: int = 5):
        self.intent = intent
        self.to_node = to_node

    def match(self, message: str) -> bool:
        return self.intent.match(message)


class Node:
    def __init__(self, name: str, strategy_switcher: StrategySwitcher, utterances: list[Utterance],
                 flow_label: str | None = None):
        self.name = name
        self.strategy_switcher = strategy_switcher
        self.utterances = utterances
        self.flow_label = flow_label

    def get_utterances(self) -> list[Utterance]:
        return [self.strategy_switcher.get_utterance(self.utterances)]


class FlowNode(Node):
    def __init__(self, name: str, strategy_switcher: StrategySwitcher, utterances: list[Utterance],
                 branches: list[Branch], next_node: Node | None = None,
                 flow_label: str | None = None, included_node: 'FlowNode' | None = None,
                 enable_branch_condition: bool = False,
                 should_transfer_to_human: bool = False):
        super().__init__(name, strategy_switcher, utterances, flow_label)
        self.included_node = included_node
        self.should_transfer_to_human = should_transfer_to_human
        self.branches = branches
        self.next_node = next_node
        self.enable_branch_condition = enable_branch_condition

    def get_utterances(self):
        result = [*super().get_utterances()]
        if not self.enable_branch_condition:
            # 没有开启分支条件，将同时读取下一节点的内容
            if self.next_node:
                next_utterances = self.next_node.get_utterances()
                result.extend(next_utterances)
        else:
            # 开启分支后，查看有没有包含节点，如果有，需要同时读出
            if self.included_node:
                included_utterances = self.included_node.get_utterances()
                result.extend(included_utterances)
        return result

    def get_branch(self, message: str) -> Branch:
        [branch for branch in self.branches if branch.match(message)]


class ActionNode(Node):
    def __init__(self, name: str, strategy_switcher: StrategySwitcher, utterances: list[Utterance],
                 flow_label: str | None = None, action: Action = Action):
        super().__init__(name, strategy_switcher, utterances, flow_label)
        self.action = action


class Scene:
    def __init__(self, name: str, intent: Intent | None = None, nodes: list[Node] = None, is_global: bool = False):
        self.name = name
        self.intent = intent
        self.nodes = nodes if nodes else []
        self.is_global = is_global


class ConversationModel:
    def __init__(self, name: str, global_setting: GlobalSetting, scenes: list[Scene]):
        self.name = name
        self.global_setting = global_setting
        self.scenes = scenes
